package org.rm.beans;

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.rm.beans.util.FacesUtil;
import org.rm.controladores.ControladorExperiencia;
import org.rm.entidades.ExperienciaBase;
import org.rm.entidades.Jugadores;
import org.rm.entidades.Partida;
import org.rm.entidades.jpa.PartidaJpaController;

public class GestorExperiencias {

	private DatosModelo modelo;
	private ControladorExperiencia experiencia;
	private Boolean experienciaTodos;

    private Map<String,ExperienciaBase> entidadesBase;
    private Map<String,List<ExperienciaBase>> listasExperiencias;
    private Partida partida;

	public GestorExperiencias() {
		experiencia = new ControladorExperiencia();
	}

	public void setModelo(DatosModelo modelo) {
		this.modelo = modelo;
	}

	public String nuevaExperiencia() {
		String name = FacesUtil.getParam("experiencia");
		Class<ExperienciaBase> clazz = GestorUtil.getEntidad(name);
        ExperienciaBase exp = entidadesBase.get(name);
        exp.setIdPartida(partida.getId());
		Map<Integer, Jugadores> jugadores = modelo.getMapaJugadores();
		if (experienciaTodos) {
			for (Jugadores jugador : modelo.getMapaJugadores().values()) {
				exp.setJugador(jugador);
				experiencia.nuevaExperiencia(exp, jugadores.values());
				listasExperiencias.put(name, experiencia.consultaExperiencias(clazz, partida.getId()));
			}
		} else {
			experiencia.nuevaExperiencia(exp, jugadores.values());
			listasExperiencias.put(name, experiencia.consultaExperiencias(clazz, partida.getId()));
		}
		return "experiencias";
	}

	public String modificaExperiencia() {
		Integer id = Integer.valueOf(FacesUtil.getParam("id"));
		String name = FacesUtil.getParam("experiencia");
		Map<Integer, Jugadores> jugadores = modelo.getMapaJugadores();		
		Class<ExperienciaBase> clazz = GestorUtil.getEntidad(name);
		
        List<ExperienciaBase> experiencias = listasExperiencias.get(name);
        for (ExperienciaBase nuevo : experiencias) {
            if (nuevo.getId().equals(id)) {
            	experiencia.modificaExperiencia(nuevo, jugadores.values());
            	listasExperiencias.put(name, experiencia.consultaExperiencias(clazz, partida.getId()));
            }
        }
		return "experiencias";
	}

	public String eliminaExperiencia() {
		Integer id = Integer.valueOf(FacesUtil.getParam("id"));
		String name = FacesUtil.getParam("experiencia");
		Map<Integer, Jugadores> jugadores = modelo.getMapaJugadores();
		Class<ExperienciaBase> clazz = GestorUtil.getEntidad(name);
		
		List<ExperienciaBase> experiencias = listasExperiencias.get(name);
        for (ExperienciaBase exp : experiencias) {
            if (exp.getId().equals(id)) {
        		experiencia.eliminaExperiencia(exp, jugadores.values());
        		listasExperiencias.put(name, experiencia.consultaExperiencias(clazz, partida.getId()));
            }
        }
		return "experiencias";
	}	

	public Boolean getExperienciaTodos() {
		return experienciaTodos;
	}

	public void setExperienciaTodos(Boolean experienciaTodos) {
		this.experienciaTodos = experienciaTodos;
	}
	
	/**
     * Devuelve un mapa donde las claves son los nombres de experiencias que
     * coinciden con {@link GestorUtil#getNombresEntidades() } y los valores
     * son listas de experiencias
     * @return mapa ['tipoExperiencia' => lista experiencias]
     */
    public Map<String,List<ExperienciaBase>> getListasExperiencias() {
        return listasExperiencias;
    }

    /**
     * Devuelve un mapa donde las claves son los nombres de experiencias que
     * coinciden con {@link GestorUtil#getNombresEntidades() } y los valores
     * son objetos de tipo {@code ExperienciaBase} utilizados por la vista
     * para que el usuario pueda crear nuevas experiencias.
     * Se trata de objetos vacíos cuyas propiedades rellena el usuario a través
     * de la vista
     * @return mapa ['tipoExperiencia' => {@code ExperienciaBase}]
     */
    public Map<String,ExperienciaBase> getEntidadesBase() {
        return entidadesBase;
    }

	/**
	 * Método que devuelve un mapa donde las claves son los nombres de
	 * experiencias que coinciden con
	 * {@link GestorUtil#getNombresEntidades() } y los valores son el número
	 * de experiencias para ese tipo. <br/> {@code getTamanyoListas().get('critico')}
	 * es igual a {@code getListasExperiencias().get('critico').size()}
	 * 
	 * @return mapa ['tipoExperiencia' => entero]
	 */
	public Map<String, Integer> getTamanyoListas() {
		Map<String, Integer> numElemlistas = new HashMap<String, Integer>();
		for (String nombre : getListasExperiencias().keySet()) {
			numElemlistas.put(nombre, getListasExperiencias().get(nombre)
					.size());
		}
		return numElemlistas;
	}

	/**
	 * Método que es llamado por el formulario de seleccionar partida.
	 * Simplemente inicializa las listas y los beans para la partida
	 * seleccionada mediante su método setter. Si partida es null, selecciona la
	 * última partida mediante el método
	 * {@link PartidaJpaController#getMaxIdPartida() }
	 * 
	 * @return la cadena 'experiencias'
	 * @see #setPartida(org.rm.entidades.Partida)
	 */
	public String seleccionaPartida() {
		if(partida == null)
			partida = PartidaJpaController.findPartida(PartidaJpaController.getMaxIdPartida());
	    inicializaListas();
	    inicializaBeans();
		return "experiencias";
	}

	private void inicializaListas() {
        listasExperiencias = new HashMap<String,List<ExperienciaBase>>();
        for (String nombre : GestorUtil.getNombresEntidades()) {
            Class clase = GestorUtil.getEntidad(nombre);
            List<ExperienciaBase> aux = experiencia.consultaExperiencias(clase, partida.getId());
            if(aux == null)
            	aux = Collections.EMPTY_LIST;
            listasExperiencias.put(nombre, aux);
        }
    }

    private void inicializaBeans() {
        entidadesBase = new HashMap<String,ExperienciaBase>();
        for (String nombre : GestorUtil.getNombresEntidades()) {
            try {
                Class<ExperienciaBase> clazz = GestorUtil.getEntidad(nombre);
                entidadesBase.put(nombre, (ExperienciaBase) clazz.newInstance());
            } catch (InstantiationException ex) {
                ex.printStackTrace();
            } catch (IllegalAccessException ex) {
                ex.printStackTrace();
            }
        }
    }

    /**
     * Método setter para el atributo partida
     * @param partida
     */
    public void setPartida(Partida partida) {
		this.partida = partida;
	}

    /**
     * Método getter para el atributo partida
     * @return el atributo partida
     */
    public Partida getPartida() {
		return partida;
	}

}
